package com.games.fifteenpieces;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Field extends SurfaceView implements SurfaceHolder.Callback{
	
	public static int PIECES_HORIZONTAL_NUMBER = 4, PIECES_VERTICAL_NUMBER = 4;
	public static final int	DIRECTION_LEFT = 0, DIRECTION_RIGHT = 1, DIRECTION_UP = 2, DIRECTION_DOWN = 3; 
	public static final String COORD_X = "x", COORD_Y = "y", COORD_DIRECTION = "d";
	private Drawable mBack;
	private Context mContext;
	private SurfaceHolder mHolder;
	private Piece[][] mPieces;
	private int mWidth, mHeight;
	private Piece mTouchedPiece = null;
	private Activity mGameActivity;
	
	
	
	public Field(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		mContext = context;
		mBack = mContext.getResources().getDrawable(R.drawable.field_back);
		mHolder = getHolder();
		//surface created, destroyed, changed callbacks
		mHolder.addCallback(this);
	}

	public void createPieces(){
		Bundle correctPlace = null;
		//create pieces
		mPieces = new Piece[PIECES_HORIZONTAL_NUMBER][PIECES_VERTICAL_NUMBER];
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				//last cell is empty
				if((i == PIECES_HORIZONTAL_NUMBER-1) && (j == PIECES_VERTICAL_NUMBER-1)){
					mPieces[j][i] = null; //there is null already, just for sure 
					continue;
				}
				
				correctPlace = new Bundle();
				correctPlace.putInt(COORD_X, i);
				correctPlace.putInt(COORD_Y, j);
				mPieces[j][i] = new Piece(mContext, correctPlace);
			}
		
	}
	public void setGameActivity(Activity activity){
		mGameActivity = activity;
	}
	
	private String makeKeyForRealCoords(int i, int j, String coord){
		return String.valueOf(i) + "_" + String.valueOf(j) + "_" + coord; 
	}

	public ArrayList<ContentValues> dump(){
		Bundle correctPlace, realPlace;
		String key = null;
		int cI = -1, cJ = -1;
		ArrayList<ContentValues> dumpList = new ArrayList<ContentValues>();
		ContentValues values;
		
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
					if(mPieces[j][i] == null) continue;
					correctPlace = mPieces[j][i].getCorrectPlace();
					realPlace = mPieces[j][i].getRealPlace();
					cI = correctPlace.getInt(COORD_X);
					cJ = correctPlace.getInt(COORD_Y);
					
					values = new ContentValues();
					
					key = makeKeyForRealCoords(cI, cJ, COORD_X);
					values.put(Saver.KEY_PIECES_KEY, key);
					values.put(Saver.KEY_PIECES_COORD, realPlace.getInt(COORD_X));
					dumpList.add(values);
					
					values = new ContentValues();
					key = makeKeyForRealCoords(cI, cJ, COORD_Y);
					values.put(Saver.KEY_PIECES_KEY, key);
					values.put(Saver.KEY_PIECES_COORD, realPlace.getInt(COORD_Y));
					dumpList.add(values);
				}
		
		return dumpList;		
	}
	
	public void load(Bundle dump){
		String key;
		int realI = -1, realJ = -1;
		Bundle correctPlace, realPlace;
		Piece piece;
		
		//create new pieces 
		mPieces = new Piece[PIECES_HORIZONTAL_NUMBER][PIECES_VERTICAL_NUMBER];
		
		
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
				for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
					correctPlace = new Bundle();
					correctPlace.putInt(COORD_X, i);
					correctPlace.putInt(COORD_Y, j);
					piece = new Piece(mContext, correctPlace);
					realPlace = new Bundle();
					key = makeKeyForRealCoords(i, j, COORD_X);
					realI = dump.getInt(key, -1);
					key = makeKeyForRealCoords(i, j, COORD_Y);
					realJ = dump.getInt(key, -1);
					if(realI >= 0 && realJ >=0){	
						realPlace.putInt(COORD_X, realI);
						realPlace.putInt(COORD_Y, realJ);
						placePieceOnPlace(piece, realPlace);
					} else { //we should come here just once: i = j = 3
						//mPieces[j][i] = null;
					}
				}
		
		//key = "!23";
		}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mTouchedPiece = getPieceByCoords((int)event.getX(), (int)event.getY());
			break;

		case MotionEvent.ACTION_UP:
			if(mTouchedPiece != null){
				boolean isMoveMade = movePiece(mTouchedPiece);
				if(isMoveMade){
					doDraw(String.valueOf(getCompletePct()));
					if(isGameOver()){
						mGameActivity.showDialog(GameActivity.DIALOG_GAME_OVER_ID);
					}
				}
				
			}
			
			break;
		}
				 
		return true;
	}

	private void doDraw(String msg){
		Canvas canvas = mHolder.lockCanvas();
		
		//Background first
		mBack.draw(canvas);
		
		//Pieces
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				if(mPieces[j][i] != null) mPieces[j][i].draw(canvas);
			}
		
		//Test message, should be deleted
		if(msg != null){
			Paint paint = new Paint();
			paint.setARGB(255, 255, 0, 0);
			canvas.drawText(msg, 30, 30, paint);
		}
		mHolder.unlockCanvasAndPost(canvas);
		
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		
	}

	private Piece getPieceByCoords(int x, int y){
		Piece res = null;
		int i = x / Piece.getWidth();
		int j = y / Piece.getHeight();
		res = mPieces[j][i];
		return res;
	}
	
	private boolean movePiece(Piece piece){
		Bundle freePlace = findFreePlaceNearPiece(piece);
		if(freePlace == null) return false;
		int ii = piece.getRealPlace().getInt(COORD_X);
		int jj = piece.getRealPlace().getInt(COORD_Y);
		placePieceOnPlace(piece, freePlace);
		mPieces[jj][ii] = null;
		return true;
	}
	
	private void placePieceOnPlace(Piece piece, Bundle place){
		piece.setRealPlace(place);
		mPieces[place.getInt(COORD_Y)][place.getInt(COORD_X)] = piece;
	}
	
	private Bundle findFreePlaceNearPiece(Piece piece){
		Bundle freePlace = null;
		int res = -1;
		Bundle b = piece.getRealPlace();
		int i = b.getInt(COORD_X);
		int j = b.getInt(COORD_Y);
		int ii = -1, jj = -1;
		Piece p = null;
		
		//try left
		if(i > 0){
			ii = i-1; jj = j;
			p = mPieces[jj][ii];
			if(p == null) res = DIRECTION_LEFT;
		}

		//try right
		if((res < 0) && (i < PIECES_HORIZONTAL_NUMBER-1)){
			ii = i+1; jj = j;
			p = mPieces[jj][ii];
			if(p == null) res = DIRECTION_RIGHT;
		}

		//try up
		if((res < 0) && (j > 0)){
			jj = j-1; ii = i;
			p = mPieces[jj][ii];
			if(p == null) res = DIRECTION_UP;
		}

		//try down
		if((res < 0) && (j < PIECES_VERTICAL_NUMBER-1)){
			jj = j+1; ii = i;
			p = mPieces[jj][ii];
			if(p == null) res = DIRECTION_DOWN;
		}

		if(res >= 0){
			freePlace = new Bundle();
			freePlace.putInt(COORD_X, ii);
			freePlace.putInt(COORD_Y, jj);
			freePlace.putInt(COORD_DIRECTION, res);
		}
		
		return freePlace;
	}
	
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Canvas c = holder.lockCanvas();
		mHeight = c.getWidth();
		mWidth = c.getHeight();
		mBack.setBounds(0, 0, mHeight, mWidth);
		holder.unlockCanvasAndPost(c);
		doDraw(null);
	}

	public boolean isGameOver(){
		boolean res = true;
		
		search:
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				if (mPieces[j][i] == null) continue;
				if (! mPieces[j][i].isOnCorrectPlace()){
					res = false;
					break search;
				}
			}		
		return res;
	}

	public void shuffle(){
		//first convert 2D array to list
		ArrayList<Piece> list = new ArrayList<Piece>();
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				list.add(mPieces[j][i]);
			}
		
		//shuffle list
		Collections.shuffle(list);
		
		//convert back list to 2Darray
		Iterator<Piece> iterator = list.iterator();
		Piece p = null;
		Bundle realPlace = null;
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				p = iterator.next();
				if(p == null) {mPieces[j][i] = null; continue;}
				realPlace = new Bundle();
				realPlace.putInt(COORD_X, i);
				realPlace.putInt(COORD_Y, j);
				p.setRealPlace(realPlace);
				mPieces[j][i] = p;
			}
		
	}
	
	public int getCompletePct(){
		int count = 0, correct = 0, res = 0;
		for(int j = 0; j < PIECES_VERTICAL_NUMBER; j++ )
			for(int i = 0; i < PIECES_HORIZONTAL_NUMBER; i++ ){
				if(mPieces[j][i] == null) continue;
				count++;
				if(mPieces[j][i].isOnCorrectPlace()) correct++;
			}	
		res = correct * 100 / count;
		return res;
	}
	
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String toString() {
		return mPieces.toString();
	}

	
}
